﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;

namespace Blank.Extends
{
    public static class CompressExtends
    {
        /// <summary>
        /// 压缩字符串
        /// </summary>
        /// <param name="toCompress"></param>
        /// <returns></returns>
        public static string CompressString(this string toCompress)
        {
            if (!string.IsNullOrEmpty(toCompress))
            {
                byte[] inBuffer = Encoding.UTF8.GetBytes(toCompress);
                using (MemoryStream compressedStream = new MemoryStream())
                {
                    using (GZipStream gzip = new GZipStream(compressedStream, CompressionMode.Compress, true))
                    {
                        gzip.Write(inBuffer, 0, inBuffer.Length);
                    }

                    compressedStream.Position = 0;
                    // store the length of the uncompressed array (inBuffer) at the first 4 bytes in outBuffer
                    byte[] outBuffer = new byte[compressedStream.Length + 4];
                    System.Buffer.BlockCopy(compressedStream.ToArray(), 0, outBuffer, 4, Convert.ToInt32(compressedStream.Length));
                    System.Buffer.BlockCopy(BitConverter.GetBytes(inBuffer.Length), 0, outBuffer, 0, 4);

                    return Convert.ToBase64String(outBuffer);
                }
            }
            else
            {
                return string.Empty;
            }
        }
        /// <summary>
        /// 解压
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="compressedString"></param>
        /// <returns></returns>
        public static void Decompress<T>(this string compressedString, out T outer)
        {
            try
            {
                if (string.IsNullOrEmpty(compressedString))
                    outer = default(T);

                // 以下代码是解压和反序列化
                byte[] toDecompressBuffer = Convert.FromBase64String(compressedString);

                using (MemoryStream decompressedStream = new MemoryStream())
                {
                    int len = BitConverter.ToInt32(toDecompressBuffer, 0);
#if !Decrypt
                    decompressedStream.Write(toDecompressBuffer, 0, toDecompressBuffer.Length);
#else
                    decompressedStream.Write(toDecompressBuffer, 4, toDecompressBuffer.Length - 4);
#endif
                    decompressedStream.Position = 0;
                    // 解压
                    using (GZipStream gzipStream = new GZipStream(decompressedStream, CompressionMode.Decompress))
                    {

                        using (MemoryStream ms3 = new MemoryStream())
                        {
                            byte[] buffer2 = new byte[4096];
                            int offset = 0;
                            while ((offset = gzipStream.Read(buffer2, 0, buffer2.Length)) != 0)
                            {
                                ms3.Write(buffer2, 0, offset);
                            }
                            BinaryFormatter formatter1 = new BinaryFormatter();
                            ms3.Position = 0;
                            // 反序列化
                            outer = (T)formatter1.Deserialize(ms3);
                        }

                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception("err:205 Decompress Cause Error", e);
            }
        }
        /// <summary>
        /// 解压缩字符串
        /// </summary>
        /// <param name="toDecompress"></param>
        /// <returns></returns>
        public static string DecompressString(this string toDecompress)
        {
            if (!string.IsNullOrEmpty(toDecompress))
            {
                byte[] toDecompressBuffer = Convert.FromBase64String(toDecompress);

                using (MemoryStream decompressedStream = new MemoryStream())
                {
                    int len = BitConverter.ToInt32(toDecompressBuffer, 0);
                    decompressedStream.Write(toDecompressBuffer, 4, toDecompressBuffer.Length - 4);
                    byte[] outBuffer = new byte[len];
                    decompressedStream.Position = 0;
                    using (GZipStream gzip = new GZipStream(decompressedStream, CompressionMode.Decompress))
                    {
                        gzip.Read(outBuffer, 0, outBuffer.Length);
                    }
                    return Encoding.UTF8.GetString(outBuffer);
                }
            }
            else
            {
                return string.Empty;
            }
        }
    }
}
